package de.tu_darmstadt.gdi1.xcom.tests.adapters;



//
import de.tu_darmstadt.gdi1.xcom.controller.XcomController;
import de.tu_darmstadt.gdi1.xcom.controller.events.ActionEnum;
import de.tu_darmstadt.gdi1.xcom.controller.events.GameStateEnum;
import de.tu_darmstadt.gdi1.xcom.controller.events.UserActionEnum;
import de.tu_darmstadt.gdi1.xcom.controller.events.XcomActionEvent;
import de.tu_darmstadt.gdi1.xcom.controller.events.XcomUserActionEvent;

/**
 * This is the testadapter for testcases for the first level of completion.
 * Implement the empty methods in this adapter and match them to your
 * concrete implementation of the game.
 * This class should not contain any game logic, you should rather only map
 * the methods to your implementation. Most of the methods should be finish
 * with at most 3 lines of code.
 * For example, the method isCorrectLevel() could look somehow like:
 * " return myGame.checkLevel(); "
 * 
 * The public student tests as well as the private tutors tests will rely on
 * the correct implementations of these methods, the other testsadapter will inherit
 * from this class as they use the basic functionality.
 * 
 * NOTE: all testcases should be executable without any userinteraction. If this
 * is required by your implementation, you should find a way to start your game in
 * XcomTestAdapterLevel1() - after this constructor ran through, the tests start and
 * will fail if manual steps are still required, and so will your testat unless you're
 * Chuck Norris.
 * 
 * @author Lukas Schwoebel
 * @author Waldemar Ankudin
 * @author Michael Zinn
 *
 */

public class XcomTestAdapterLevel1 {
	
	// 
	protected XcomController testImpl;
	
	/**
	 * start an instance of your implementation here. Be sure that it is running
	 * afterwards, so no login-screen or anything is visible or at least no login
	 * or any manual action is needed!
	 */
	public XcomTestAdapterLevel1() {
		// TODO: fill stub
		testImpl = new XcomController();
		testImpl.loadedFromTest = true;
	}
	
	/**
	 * in this method you get a string-representation of a level. This will eventually
	 * include all extended level-information like actions for switches or
	 * doors. In level 1 testcases you can ignore most of the information, but the higher
	 * level tests are relying on this method.
	 * After this method is finished, the given level should be loaded in your
	 * implementation.
	 * Line-breaks will be delimited as \n. You should not run any validity-test in
	 * this method or at least this should not influence the loading of the level.
	 * All other tests assume, that this level is hold by your implementation until
	 * the next one is loaded!
	 * NOTE: there is no "loadSavegame"-method in any of the adapters, as all needed
	 * gamestate-information is in the levelfile itself. So if a "savegame" is needed
	 * later on, still this method will be called
	 * 
	 * @param level
	 * 		string representation of the level as described in the game-document.
	 */
	public void loadLevelFromString(String level) {
		// TODO: fill stub
		
		testImpl.loadLevel(level);
	}
	
	/**
	 * return the *current* representation of the level as string. You can handle doors
	 * and switches as floor and walls here. Ignore any extra-information about
	 * states of doors and switches as well as directions / actionpoints of mobile
	 * units such as "humans" or "aliens", just return @ or Z on the field they are
	 * placed. Insert \n for a line-break.
	 * If the level is invalid, it is allowed to return an empty string here.
	 */
	public String levelRepresentationAsString() {
		// TODO: fill stub
		if(testImpl.getGd() == null) return "";
		return testImpl.getGd().returnGameState();
	}
	
	/**
	 * return in this method, if the level, given by the level-string in loadLevelFromString()
	 * is valid. if you implement higher levels, this will include the correctness check of 
	 * doors/switches and extended gamestate information for "mobs". See in the game-document
	 * for the requirements.
	 * @param level 
	 * 
	 * @return boolean
	 * 			was the loaded level a valid one
	 */
	public boolean isCorrectLevel(String level) {
		
		return testImpl.verifyLevel(level);

	}

	/**
	 * return the char/string-representation of the element defined by x and y, where
	 * x = 0, y = 0 defines the upper left corner of the game-area.
	 * return a single char for the game-field as defined in the game-document. If a player
	 * or a alien is on the specified field, you can ignore its direction and just return '@'
	 * or 'Z'.
	 * NOTE: As you could ignore doors and switches in the first level of implementation, the
	 * tests will be correct if you return the char for a floor-element instead. If your
	 * implementation handles doors and switches already, they won't fail either if you return
	 * the correct element. Also here, ignore states of doors and switches and just return c and
	 * = if you are that far. Anyways, returning '.' instead won't fail *this* testcase.
	 * NOTE2: if in later implementation levels in a testcase a player or zombie walks into/onto
	 * a field of an open door, return '@' or 'Z' in here and ignore the door. In all other cases
	 * return '=' even if the door is open
	 */
	public char elementOnPosition(int x, int y) {
		// TODO: fill stub
		return testImpl.getGd().getTopGameElement(x, y).charAt(0);
	}
	
	/**
	 * rotate the active player of the active team. Per default without having set
	 * an active player, the first player of the team mentioned in the level-string
	 * should be active.
	 */
	public void rotateActivePlayer(boolean clockwise) {
		// TODO: fill stub
		if(clockwise)
			testImpl.processEvent(new XcomActionEvent(ActionEnum.RotateRight));
		else
			testImpl.processEvent(new XcomActionEvent(ActionEnum.RotateLeft));
	}
	
	/**
	 * perform an action for the currently active player. If the field in the direction
	 * he is looking to is empty, move to it, otherwise attack an enemy - or in later
	 * implementation levels, use a switch.
	 * This method does not cover a *shooting*-action in later implementation levels.
	 */
	public void performActionForActivePlayer() {
		// TODO: fill stub
		testImpl.processEvent(new XcomActionEvent(ActionEnum.Attack));
	}
	
	/**
	 * handle a mouseclick-action here on the field with coordinates x and y,
	 * where x=0, y=0 is the upper left corner.
	 */
	public void clickPerformedAt(int x, int y) {
		// TODO: fill stub

		XcomUserActionEvent event = new XcomUserActionEvent(UserActionEnum.FieldClicked);
		event.setIntOne(x);
		event.setIntTwo(y);
		testImpl.processEvent(event);
	}
	
	/**
	 * return the number of action points the current active player has left.
	 * 
	 * @return int
	 * 			the number of action-points left for the active player of the
	 * 			active team
	 */
	public int actionPointsLeft() {
		// TODO: fill stub
		return testImpl.getGd().getActiveTeam().getCurrentMob().getPoints();
	}
	
	/**
	 * return in this method the direction the active player is looking to, whereas
	 * 1 = NORTH (the default direction at levelloading)
	 * 2 = EAST
	 * 3 = SOUTH
	 * 4 = WEST
	 */
	public int activePlayerLookingToDirection() {
		// TODO: fill stub
		switch(testImpl.getGd().getActiveTeam().getCurrentMob().getDirection()) {
			case North: return 1;
			case East: return 2;
			case South: return 3;
			case West: return 4;
			default: return 0;
		}
	}
	
	/**
	 * change to the active player (/human) on the given position by
	 * x and y, where x=0,y=0 is the left upper corner.
	 * If no human is on this position, the method should not change anything,
	 * or rather leave the current player active
	 */
	public void changeActivePlayer(int x, int y) {
		// TODO: fill stub
		testImpl.getKeyFromMouse(x, y);
	}
	
	/** return here, if the current level is won
	 */
	public boolean isWon() {
		// TODO: fill stub
		if(testImpl.getGd() == null) return false;
		
		return testImpl.getGd().isWon();
	}
	
	/** return here, if the current level is lost
	 */
	public boolean isLost() {
		// TODO: fill stub
		if(testImpl.getGd() == null) return true;
		
		return testImpl.getGd().isLost();
	}
	
	/**
	 * end the turn in this method. By calling this method, automatically
	 * a new turn for the humans should begin, the aliens should not do anything.
	 * As in later implementation levels there is the KI/AI for aliens, there will
	 * be another method for this in "higher" testadapters. As far as this
	 * method is concerned you should just "ignore" the turn of aliens here if you
	 * included the KI for your implementation.
	 * Also there should be no delay. So if you implemented "splash-screens" to visualise
	 * the end of a turn or something like that, find a way to deactivate it while the
	 * tests are running.
	 */
	public void endTurn() {
		// TODO: fill stub
		testImpl.processEvent(new XcomActionEvent(ActionEnum.EndTurn));
	}
}
